package com.iplant.wms.serviceImpl.dao.bill;

import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.wms.service.basicenum.bill.WMSOutboundOrderStatus;
import com.iplant.wms.service.basicenum.wms.WMSStockRecordType;
import com.iplant.wms.service.po.asn.WMSReceiveBill;
import com.iplant.wms.service.po.asn.WMSReceiveBillItem;
import com.iplant.wms.service.po.bill.WMSOutboundOrder;
import com.iplant.wms.service.po.bill.WMSOutboundOrderItem;
import com.iplant.wms.service.po.bill.WMSSalesDelivery;
import com.iplant.wms.service.po.bill.WMSSalesDeliveryItem;
import com.iplant.wms.service.po.mfs.WMSStoreStation;
import com.iplant.wms.serviceImpl.dao.asn.WMSReceiveBillItemDAO;
import com.iplant.wms.serviceImpl.dao.wms.WMSSalesDeliveryItemDAO;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@DBBaseDAO(WMSOutboundOrder.class)
public class WMSOutboundOrderDAO extends BaseDAO {

    private static WMSOutboundOrderDAO Instance = null;

    private WMSOutboundOrderDAO() {
        super("");
        this.Init();
    }

    public static WMSOutboundOrderDAO getInstance() {
        if (Instance == null) {
            Instance = new WMSOutboundOrderDAO();
        }
        return Instance;
    }

    public List<WMSOutboundOrder> WMS_SelectOutboundOrderList(BMSEmployee wLoginUser, int wSalesDeliveryID, Pagination wPagination, OutResult<Integer> wErrorCode) {
        List<WMSOutboundOrder> wResult = new ArrayList<WMSOutboundOrder>();
        try {
            Map<String, Object> wParams = new HashMap<>();

            wParams.put("SalesDeliveryID", wSalesDeliveryID);

            wResult = this.SelectPOList(wLoginUser, wParams, wPagination, wErrorCode);

        } catch (Exception e) {
            log.error(e.toString());
            wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
        }
        return wResult;
    }

    public WMSOutboundOrder WMS_SelectOutboundOrderByReceiveBillID(BMSEmployee wLoginUser, int wReceiveBillID,OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();

        wParams.put("ReceiveBillID", wReceiveBillID);

        List<WMSOutboundOrder> wList = this.SelectPOList(wLoginUser, wParams, Pagination.getMaxSize(WMSOutboundOrder.class), wErrorCode);

        if (wList != null && wList.size() > 0)
            return wList.get(0);

        return new WMSOutboundOrder();
    }

    public WMSOutboundOrder WMS_SelectOutboundOrderBySalesDeliveryID(BMSEmployee wLoginUser, int wSalesDeliveryID,OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();

        wParams.put("SalesDeliveryID", wSalesDeliveryID);

        List<WMSOutboundOrder> wList = this.SelectPOList(wLoginUser, wParams, Pagination.getMaxSize(WMSOutboundOrder.class), wErrorCode);

        if (wList != null && wList.size() > 0)
            return wList.get(0);

        return new WMSOutboundOrder();
    }


    public WMSOutboundOrder WMS_SelectOutboundOrderByTaskID(BMSEmployee wLoginUser, int wTaskDayID, int wType, OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();

        if (wTaskDayID <= 0 || wType <= 0) {
            wErrorCode.Result = ExceptionTypes.Parameter.getValue();
            return new WMSOutboundOrder();
        }

        wParams.put("TaskDayID", wTaskDayID);
        wParams.put("Type", wType);
        List<WMSOutboundOrder> wList = this.SelectPOList(wLoginUser, wParams, Pagination.getMaxSize(WMSOutboundOrder.class), wErrorCode);

        if (wList != null && wList.size() > 0)
            return wList.get(0);

        return new WMSOutboundOrder();
    }


    /**
     * 通过收货单创建入库单
     *
     * @param wLoginUser      用户
     * @param wWMSReceiveBill 收货单（包括子项）
     * @param wErrorCode      错误代码
     * @return 入库单（包括子项）
     */
    public WMSOutboundOrder WMS_CreateFromReceiveBill(BMSEmployee wLoginUser, WMSReceiveBill wWMSReceiveBill, OutResult<Integer> wErrorCode) {
        WMSOutboundOrder wResult = new WMSOutboundOrder();
        // 生成的主单据ID，若子单据生成过程中异常，可回滚；
        // 处理子项时的ErrorCode，防止自带ErrorCode被回滚函数给复位成0，无法返回给前端的错误情况；
        try {

            if (wWMSReceiveBill == null || wWMSReceiveBill.ID <= 0 || StringUtils.isEmpty(wWMSReceiveBill.getCode())) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            wResult = WMSOutboundOrderDAO.getInstance().WMS_SelectOutboundOrderByReceiveBillID(wLoginUser, wWMSReceiveBill.ID,  wErrorCode);

            if(wErrorCode.Result!=0)
                return wResult;

            if (wWMSReceiveBill.ItemList == null || wWMSReceiveBill.ItemList.size() == 0) {
                wWMSReceiveBill.ItemList = WMSReceiveBillItemDAO.getInstance().WMS_SelectListByReceiveBillID(wLoginUser, wWMSReceiveBill.ID, Pagination.getMaxSize(WMSReceiveBillItem.class), wErrorCode);
                if (wErrorCode.Result != 0) {
                    return wResult;
                }
            }
            // 主单据
            wResult.FactoryID = wWMSReceiveBill.FactoryID;
            wResult.FactoryCode = wWMSReceiveBill.FactoryCode;
            wResult.FactoryName = wWMSReceiveBill.FactoryName;
            wResult.U8_PUArrivalVouchID = wWMSReceiveBill.ArrivalNoticeID;
            wResult.U8_PUArrivalVouchCode = wWMSReceiveBill.ArrivalNoticeCode;
            wResult.ReceiveBillID = wWMSReceiveBill.ID;
            wResult.ReceiveBillCode = wWMSReceiveBill.Code;
            wResult.Description = wWMSReceiveBill.Description;
            if (wWMSReceiveBill.ArrivalNoticeID > 0) {
                wResult.setType(WMSStockRecordType.ProcurementAndWarehousing.getValue());
            } else {
                wResult.setType(WMSStockRecordType.GeneralWarehousing.getValue());
            }
            wResult.Status = WMSOutboundOrderStatus.Saved.getValue();
            wResult.setUserInfo(wLoginUser);
            // 保存主单据以获得ID给子项
            this.UpdatePo(wLoginUser, wResult, wErrorCode);
            if (wErrorCode.Result != 0 || wResult.ID <= 0) {
                return wResult;
            }

            // 物料清单
            wWMSReceiveBill.ItemList.removeIf(p -> p.MaterialID <= 0);
            if (wWMSReceiveBill.ItemList.size() == 0) {
                log.warn("WMS_CreateFromReceiveBill", "有效的物料清单为空。");
                return wResult;
            }
            WMSStoreStation wmsStoreStation;
            for (WMSReceiveBillItem wWMSReceiveBillItem : wWMSReceiveBill.ItemList) {
                WMSOutboundOrderItem wOutboundOrderItem = new WMSOutboundOrderItem();

                wOutboundOrderItem.FactoryID = wWMSReceiveBillItem.FactoryID;
                wOutboundOrderItem.FactoryCode = wWMSReceiveBillItem.FactoryCode;
                wOutboundOrderItem.FactoryName = wWMSReceiveBillItem.FactoryName;
                wOutboundOrderItem.OutboundOrderID = wResult.ID;
                wOutboundOrderItem.OutboundOrderCode = wResult.Code;
                wOutboundOrderItem.ReceiveBillItemID = wWMSReceiveBillItem.ID;
                wOutboundOrderItem.U8_ItemID = wWMSReceiveBillItem.U8_UAArrivalNoticeItemID;
                wOutboundOrderItem.U8_BillID = wWMSReceiveBillItem.U8_UAArrivalNoticeID;
                wOutboundOrderItem.ProjectNo = wWMSReceiveBillItem.ProjectNo;
                wOutboundOrderItem.ProjectName = wWMSReceiveBillItem.ProjectName;
                wOutboundOrderItem.MaterialID = wWMSReceiveBillItem.MaterialID;
                wOutboundOrderItem.MaterialCode = wWMSReceiveBillItem.MaterialCode;
                wOutboundOrderItem.MaterialName = wWMSReceiveBillItem.MaterialName;
                wOutboundOrderItem.FQTY = wWMSReceiveBillItem.ReceiveQuantity;
                wOutboundOrderItem.UnitID = wWMSReceiveBillItem.ReceiveUnit;
                wOutboundOrderItem.UnitText = wWMSReceiveBillItem.ReceiveUnitText;
                wOutboundOrderItem.TotalVolume = wWMSReceiveBillItem.TotalVolume;
                wOutboundOrderItem.TotalGrossWeight = wWMSReceiveBillItem.TotalGrossWeight;
                wOutboundOrderItem.TotalNetWeight = wWMSReceiveBillItem.TotalNetWeight;
                wOutboundOrderItem.TotalPrice = wWMSReceiveBillItem.TotalPrice;
                wOutboundOrderItem.BatchRecordID = wWMSReceiveBillItem.BatchRecordID;
                wOutboundOrderItem.BatchRecordCode = wWMSReceiveBillItem.BatchRecordCode;
                wOutboundOrderItem.StockTypeID = 0;//需要填写
                wOutboundOrderItem.StoreID = wWMSReceiveBillItem.ReceiveStoreID;
                wOutboundOrderItem.StoreCode = wWMSReceiveBillItem.ReceiveStoreCode;
                wOutboundOrderItem.StoreName = wWMSReceiveBillItem.ReceiveStoreName;
                wOutboundOrderItem.cItem_name = wWMSReceiveBillItem.cItem_name;
                wOutboundOrderItem.cItem_class = wWMSReceiveBillItem.cItem_class;
                wOutboundOrderItem.Description = wWMSReceiveBillItem.Description;

                if (wWMSReceiveBillItem.ReceiveStationID > 0) {
                    wmsStoreStation = CacheUtils.GetCacheInfo(WMSStoreStation.class, wWMSReceiveBillItem.ReceiveStationID, "");
                    wOutboundOrderItem.StoreStationID = wmsStoreStation.ID;
                    wOutboundOrderItem.StoreStationCode = wmsStoreStation.Code;
                    wOutboundOrderItem.StoreStationName = wmsStoreStation.Name;
                    wOutboundOrderItem.StoreAreaID = wmsStoreStation.StoreAreaID;
                    wOutboundOrderItem.StoreAreaName = wmsStoreStation.StoreAreaName;
                    wOutboundOrderItem.StoreAreaCode = wmsStoreStation.StoreAreaCode;
                    wOutboundOrderItem.StoreShelfID = wmsStoreStation.StoreShelfID;
                    wOutboundOrderItem.StoreShelfName = wmsStoreStation.StoreShelfName;
                    wOutboundOrderItem.StoreShelfCode = wmsStoreStation.StoreShelfCode;
                    wOutboundOrderItem.StoreRegionID = wmsStoreStation.StoreRegionID;
                    wOutboundOrderItem.StoreRegionName = wmsStoreStation.StoreRegionName;
                    wOutboundOrderItem.StoreRegionCode = wmsStoreStation.StoreRegionCode;
                }


                wOutboundOrderItem.setUserInfo(wLoginUser);
                wResult.ItemList.add(wOutboundOrderItem);
            }
            // 之所以没有用BasePO的UpdatePo逐个保存，是此过程作为一个整体执行，避免中途报错无法回滚，因此带来的问题是无法自动生成Code；
            WMSOutboundOrderItemDAO.getInstance().UpdatePoList(wLoginUser, wResult.ItemList, wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_CreateFromReceiveBill", ex);
        }
        // 如果出错了，且主单据插入成功，则删掉主单据
        if (wErrorCode.Result != 0 && wResult != null && wResult.ID > 0) {
            this.DeletePO(wLoginUser, wResult, new OutResult<Integer>(0));
        }
        return wResult;
    }

    /**
     * 通过发货单创建出库单
     *
     * @param wLoginUser        用户
     * @param wWMSSalesDelivery 收货单（包括子项）
     * @param wErrorCode        错误代码
     * @return 入库单（包括子项）
     */
    public WMSOutboundOrder WMS_CreateFromSalesDelivery(BMSEmployee wLoginUser, WMSSalesDelivery wWMSSalesDelivery, OutResult<Integer> wErrorCode) {
        WMSOutboundOrder wResult = new WMSOutboundOrder();
        // 生成的主单据ID，若子单据生成过程中异常，可回滚；
        // 处理子项时的ErrorCode，防止自带ErrorCode被回滚函数给复位成0，无法返回给前端的错误情况；
        try {

            if (wWMSSalesDelivery == null || wWMSSalesDelivery.ID <= 0 || StringUtils.isEmpty(wWMSSalesDelivery.getCode())) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            wResult = WMSOutboundOrderDAO.getInstance().WMS_SelectOutboundOrderBySalesDeliveryID(wLoginUser, wWMSSalesDelivery.ID,  wErrorCode);

            if(wErrorCode.Result!=0)
                return wResult;

            if (wWMSSalesDelivery.ItemList == null || wWMSSalesDelivery.ItemList.size() == 0) {
                wWMSSalesDelivery.ItemList = WMSSalesDeliveryItemDAO.getInstance().WMS_SelectSalesDeliveryItemList(wLoginUser,
                        wWMSSalesDelivery.ID, -1, Pagination.getMaxSize(WMSSalesDeliveryItem.class), wErrorCode);
                if (wErrorCode.Result != 0) {
                    return wResult;
                }
            }
            // 主单据
            wResult.FactoryID = wWMSSalesDelivery.FactoryID;
            wResult.FactoryCode = wWMSSalesDelivery.FactoryCode;
            wResult.FactoryName = wWMSSalesDelivery.FactoryName;
            wResult.SalesDeliveryID = wWMSSalesDelivery.ID;
            wResult.U8_PUSalesDeliveryID = wWMSSalesDelivery.U8_BillID;
            wResult.U8_PUSalesDeliveryCode = wWMSSalesDelivery.U8_BillCode;
            wResult.SalesDeliveryCode = wWMSSalesDelivery.Code;
            wResult.DeliveryTime = wWMSSalesDelivery.DeliveryTime;
            wResult.Description = wWMSSalesDelivery.Description;
            if (wWMSSalesDelivery.PurchaseOrderID > 0) {
                wResult.setType(WMSStockRecordType.SalesOutOfStock.getValue());
            } else {
                wResult.setType(WMSStockRecordType.GeneralOutOfStock.getValue());
            }
            wResult.Status = WMSOutboundOrderStatus.Saved.getValue();
            wResult.setUserInfo(wLoginUser);
            // 保存主单据以获得ID给子项
            this.UpdatePo(wLoginUser, wResult, wErrorCode);
            if (wErrorCode.Result != 0 || wResult.ID <= 0) {
                return wResult;
            }
            // 物料清单
            wWMSSalesDelivery.ItemList.removeIf(p -> p.MaterialID <= 0);
            if (wWMSSalesDelivery.ItemList.size() == 0) {
                log.warn("WMS_CreateFromSalesDelivery", "有效的物料清单为空。");
                return wResult;
            }

            for (WMSSalesDeliveryItem wWMSSalesDeliveryItem : wWMSSalesDelivery.ItemList) {
                WMSOutboundOrderItem wOutboundOrderItem = new WMSOutboundOrderItem();

                wOutboundOrderItem.FactoryID = wWMSSalesDeliveryItem.FactoryID;
                wOutboundOrderItem.FactoryCode = wWMSSalesDeliveryItem.FactoryCode;
                wOutboundOrderItem.FactoryName = wWMSSalesDeliveryItem.FactoryName;
                wOutboundOrderItem.OutboundOrderID = wResult.ID;
                wOutboundOrderItem.OutboundOrderCode = wResult.Code;
                wOutboundOrderItem.ReceiveBillItemID = wWMSSalesDeliveryItem.ID;
                wOutboundOrderItem.U8_BillID = wWMSSalesDeliveryItem.U8_BillID;
                wOutboundOrderItem.U8_ItemID = wWMSSalesDeliveryItem.U8_BillItemID;
                wOutboundOrderItem.ProjectNo = wWMSSalesDeliveryItem.ProjectNo;
                wOutboundOrderItem.MaterialID = wWMSSalesDeliveryItem.MaterialID;
                wOutboundOrderItem.MaterialCode = wWMSSalesDeliveryItem.MaterialNo;
                wOutboundOrderItem.MaterialName = wWMSSalesDeliveryItem.MaterialName;
                wOutboundOrderItem.FQTY = wWMSSalesDeliveryItem.FQTY;
                wOutboundOrderItem.UnitID = wWMSSalesDeliveryItem.UnitID;
                wOutboundOrderItem.UnitText = wWMSSalesDeliveryItem.UnitText;
                wOutboundOrderItem.TotalVolume = 0;
                wOutboundOrderItem.TotalGrossWeight = 0;
                wOutboundOrderItem.TotalNetWeight = 0;
                wOutboundOrderItem.TotalPrice = 0;
                wOutboundOrderItem.BatchRecordID = 0;
                wOutboundOrderItem.BatchRecordCode = "";
                wOutboundOrderItem.StockTypeID = 0;//需要填写
                wOutboundOrderItem.cItem_name = wWMSSalesDeliveryItem.cItem_name;
                wOutboundOrderItem.cItem_class = wWMSSalesDeliveryItem.cItem_class;
                wOutboundOrderItem.Description = wWMSSalesDeliveryItem.Description;

                wOutboundOrderItem.setUserInfo(wLoginUser);
                wResult.ItemList.add(wOutboundOrderItem);
            }
            // 之所以没有用BasePO的UpdatePo逐个保存，是此过程作为一个整体执行，避免中途报错无法回滚，因此带来的问题是无法自动生成Code；
            WMSOutboundOrderItemDAO.getInstance().UpdatePoList(wLoginUser, wResult.ItemList, wErrorCode);

        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            log.error("WMS_CreateFromSalesDelivery", ex);
        }
        // 如果出错了，且主单据插入成功，则删掉主单据
        if (wErrorCode.Result != 0 && wResult != null && wResult.ID > 0) {
            this.DeletePO(wLoginUser, wResult, new OutResult<Integer>(0));
        }
        return wResult;
    }
}
